package com.jltx.xq.coroutinesandrxpro.ext

import android.app.Activity
import androidx.annotation.MainThread
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlin.reflect.KClass

/**
 * @author aidenquan
 *         Created by junlintianxia on 2021/08/12.
 */

@MainThread
inline fun <reified VM : ViewModel> ViewModelStoreOwner.activityViewModels(
    noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null
): Lazy<VM> {
    val activity: Activity = when (this) {
        is Activity -> {
            this
        }
        is Fragment -> {
            this.requireActivity()
        }
        else -> throw IllegalArgumentException(
            "ViewModel can be accessed only when Activity is null"
        )
    }
    return createViewModelLazy(activity, VM::class, {
        val fragmentActivity: FragmentActivity =
            activity as? FragmentActivity ?: throw IllegalArgumentException(
                "Activity should be FragmentActivity subclass"
            )
        fragmentActivity.viewModelStore
    }, factoryProducer)
}

@MainThread
inline fun <reified VM : ViewModel> ViewModelStoreOwner.viewModels(
    noinline ownerProducer: () -> ViewModelStoreOwner = { this },
    noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null
): Lazy<VM> {
    val activity: Activity = when (this) {
        is Activity -> {
            this
        }
        is Fragment -> {
            this.requireActivity()
        }
        else -> throw IllegalArgumentException(
            "ViewModel can be accessed only when Activity is null"
        )
    }
    return createViewModelLazy(
        activity,
        VM::class,
        { ownerProducer().viewModelStore },
        factoryProducer
    )
}

@MainThread
fun <VM : ViewModel> ViewModelStoreOwner.createViewModelLazy(
    activity: Activity,
    viewModelClass: KClass<VM>,
    storeProducer: () -> ViewModelStore,
    factoryProducer: (() -> ViewModelProvider.Factory)? = null
): Lazy<VM> {
    val factoryPromise = factoryProducer ?: {
        val application = activity?.application ?: throw IllegalStateException(
            "ViewModel can be accessed only when Scene is attached"
        )
        ViewModelProvider.AndroidViewModelFactory.getInstance(application)
    }
    return ViewModelLazy(viewModelClass, storeProducer, factoryPromise)
}
